﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Runtime.InteropServices;
using Ppt = Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Tools;
using MVVM.Core;
using ViewComponents.PowerPoint;

namespace PSCharts
{
    public class ViewModelContainer
    {
        ViewModelBase mViewModel;

        public ViewModelContainer(ViewModelBase viewModel)
        {
            mViewModel = viewModel;
        }

        public Control View { get { return mViewModel.View; } }

        public CustomTaskPane TaskPane { get; set; }
    }

    public class ViewModelManager
    {
        readonly Ppt.Application mApp = Globals.ThisAddIn.Application;
        readonly Dictionary<Ppt.Presentation, ViewModelContainer> mContainers = new Dictionary<Ppt.Presentation, ViewModelContainer>();

        public ViewModelManager()
        {            
            foreach (Ppt.Presentation pres in mApp.Presentations)
                Add(pres);
            
            HookUpEvents();
        }

        void HookUpEvents()
        {
            mApp.AfterNewPresentation += App_AfterNewPresentation;
            mApp.PresentationOpen += App_PresentationOpen;
            mApp.PresentationClose += App_PresentationClose;
        }

        void App_AfterNewPresentation(Ppt.Presentation Pres)
        {
            Add(Pres);
        }

        void App_PresentationOpen(Ppt.Presentation Pres)
        {
            // Deal with the case where the blank presentation on startup is discarded when
            // another presentation is opened.
            CheckForOrphanedViewModel();

            Add(Pres);
        }

        void App_PresentationClose(Ppt.Presentation Pres)
        {
            Remove(Pres);
        }

        void Add(Ppt.Presentation pres)
        {
            if (!mContainers.ContainsKey(pres))
            {
                // Create ViewModel, assign a CustomTaskPane and add to dictionary.
                ViewModelContainer container = new ViewModelContainer(PPTViewModelFactory.CreateLinkedTextRangeViewModel(pres));
                container.TaskPane = CreateCustomTaskPane(container.View, pres.Windows[1], pres.Name);
                mContainers.Add(pres, container);
            }
        }

        CustomTaskPane CreateCustomTaskPane(UIElement control, Ppt.DocumentWindow wn, string title)
        {
            // Create a WPF element host.
            System.Windows.Forms.Integration.ElementHost host = new System.Windows.Forms.Integration.ElementHost();
            host.Dock = System.Windows.Forms.DockStyle.Fill;
            host.Child = control;

            // Create a user control to contain the WPF element host.
            System.Windows.Forms.UserControl uc = new System.Windows.Forms.UserControl();
            uc.Controls.Add(host);

            // Create a custom task pane and add the user control.
            CustomTaskPane ctp = Globals.ThisAddIn.CustomTaskPanes.Add(uc, title, wn);
            ctp.Visible = true;

            return ctp;
        }

        void Remove(Ppt.Presentation pres)
        {
            if (mContainers.ContainsKey(pres))
            {
                Globals.ThisAddIn.CustomTaskPanes.Remove(mContainers[pres].TaskPane);
                mContainers.Remove(pres);
            }
        }

        void CheckForOrphanedViewModel()
        {
            // After a presentation has been opened but before a view model has been created
            // for it, if there are already as many view models as open presentations
            // then assume that one of the view models has been orphaned from it's presentation.
            // This tends to happen when PowerPoint discards the blank presentation it opens with
            // when another presentation is opened.
            if (mApp.Presentations.Count == mContainers.Count)
            {
                foreach (Ppt.Presentation pres in mContainers.Keys)
                {
                    try { string name = pres.Name; }
                    catch (COMException)
                    {
                        Globals.ThisAddIn.CustomTaskPanes.Remove(mContainers[pres].TaskPane);
                        break;
                    }
                }   
            }
        }
    }
}
